use crate::phi::data::Rectangle;
use crate::phi::gfx::{CopySprite, Sprite};
use crate::phi::{Phi, View, ViewAction};
use crate::views::game::Background;
use crate::views::DEBUG;
use sdl2::pixels::Color;

pub struct Menu {
    actions: Vec<Action>,
    selected: i8,

    bg_back: Background,
    bg_middle: Background,
    bg_front: Background,
}

impl Menu {
    pub fn new(context: &mut Phi) -> Self {
        use crate::views::game::ShipView;
        Self {
            actions: vec![
                Action::new(
                    context,
                    "New Game",
                    Box::new(|phi| {
                        ViewAction::ChangeView(Box::new(
                            ShipView::new(phi),
                        ))
                    }),
                ),
                Action::new(context, "Quit", Box::new(|_| ViewAction::Quit)),
            ],
            selected: 0,
            bg_front: Background {
                pos: 0.0,
                vel: 80.0,
                sprite: Sprite::load(&mut context.canvas, "assets/star_fg.png")
                    .unwrap(),
            },
            bg_middle: Background {
                pos: 0.0,
                vel: 40.0,
                sprite: Sprite::load(&mut context.canvas, "assets/star_mg.png")
                    .unwrap(),
            },
            bg_back: Background {
                pos: 0.0,
                vel: 20.0,
                sprite: Sprite::load(&mut context.canvas, "assets/star_bg.png")
                    .unwrap(),
            },
        }
    }
}

impl View for Menu {
    fn render(&mut self, context: &mut Phi, elapsed: f64) -> ViewAction {
        let events = &context.events;
        if events.now.quit || events.now.key_escape == Some(true) {
            return ViewAction::Quit;
        }

        if events.now.key_space == Some(true) {
            return (self.actions[self.selected as usize].func)(context);
        }

        if events.now.key_up == Some(true) {
            self.selected -= 1;
            if self.selected < 0 {
                self.selected = self.actions.len() as i8 - 1;
            }
        }

        if events.now.key_down == Some(true) {
            self.selected += 1;
            if self.selected >= self.actions.len() as i8 {
                self.selected = 0;
            }
        }

        let (win_w, win_h) = context.output_size();
        let canvas = &mut context.canvas;

        canvas.set_draw_color(Color::RGB(0, 0, 0));
        canvas.clear();

        self.bg_back.render(canvas, elapsed);
        self.bg_middle.render(canvas, elapsed);
        self.bg_front.render(canvas, elapsed);

        let label_h = 50.0;
        let border_width: f64 = 3.0;
        let box_w = 360.0;
        let box_h = self.actions.len() as f64 * label_h;
        let margin_h = 10.0;

        if DEBUG {
            canvas.set_draw_color(Color::RGB(70, 15, 70));
            canvas
                .fill_rect(
                    Rectangle {
                        w: border_width.mul_add(2.0, box_w),
                        h: box_h + border_width * 2.0 + margin_h * 2.0,
                        x: (win_w - box_w) / 2.0 - border_width,
                        y: (win_h - box_h) / 2.0 - margin_h - border_width,
                    }
                    .to_sdl()
                    .unwrap(),
                )
                .unwrap();

            canvas.set_draw_color(Color::RGB(140, 30, 140));
            canvas
                .fill_rect(
                    Rectangle {
                        w: box_w,
                        h: margin_h.mul_add(2.0, box_h),
                        x: (win_w - box_w) / 2.0,
                        y: (win_h - box_h) / 2.0 - margin_h,
                    }
                    .to_sdl()
                    .unwrap(),
                )
                .unwrap();
        }

        self.actions.iter().enumerate().for_each(|(i, action)| {
            if self.selected as usize == i {
                let (w, h) = action.hover_sprite.size();
                canvas.copy_sprite(
                    &action.hover_sprite,
                    Rectangle {
                        x: (win_w - w) / 2.0,
                        y: (win_h - box_h + label_h - h) / 2.0
                            + label_h * i as f64,
                        w,
                        h,
                    },
                );
            } else {
                let (w, h) = action.idle_sprite.size();
                canvas.copy_sprite(
                    &action.idle_sprite,
                    Rectangle {
                        x: (win_w - w) / 2.0,
                        y: (win_h - box_h + label_h - h) / 2.0
                            + label_h * i as f64,
                        w,
                        h,
                    },
                );
            }
        });
        ViewAction::None
    }
}

struct Action {
    func: Box<dyn Fn(&mut Phi) -> ViewAction>,
    idle_sprite: Sprite,
    hover_sprite: Sprite,
}

impl Action {
    fn new(
        context: &mut Phi,
        label: &'static str,
        func: Box<dyn Fn(&mut Phi) -> ViewAction>,
    ) -> Self {
        Action {
            func,
            idle_sprite: context
                .ttf_str_sprite(
                    label,
                    "assets/belligerent.ttf",
                    32,
                    Color::RGB(220, 220, 220),
                )
                .expect("Failed to load idle sprite font"),
            hover_sprite: context
                .ttf_str_sprite(
                    label,
                    "assets/belligerent.ttf",
                    38,
                    Color::RGB(255, 255, 255),
                )
                .expect("Failed to load hover sprite font"),
        }
    }
}
